package com.test;

import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.util.Iterator;
import java.util.Set;

public class EchoSever {
	private Selector selector; // 事件监听器 查看是否发生了某种监听事件
	private ServerSocketChannel serverSocketChannel; // 打开端口 接收端口
	private int port = 8000;
	private Charset charset = Charset.forName("GBK");

	public EchoSever() throws Exception {
		selector = Selector.open();
		serverSocketChannel = ServerSocketChannel.open();
		// 工作模式调成非阻塞模式
		serverSocketChannel.configureBlocking(false);
		serverSocketChannel.socket().setReuseAddress(true); // 方便端口重启 服务器重启需要等很长时间 这样就不会等很久
		serverSocketChannel.socket().bind(new InetSocketAddress(port));
	}

	public void service() throws Exception {
		// 必须会写
		serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
		while (true) {
			// 检查是否发生了就绪时间 如果发生了就处理它
			int n = selector.select(); // select是以阻塞模式等着 一直等着直到发生了就绪实践 或者当期线程关闭
			if (n == 0)		// 至少有一个就绪事件发生
				continue;
			Set<SelectionKey> readkeys = selector.selectedKeys(); 
			Iterator<SelectionKey> iterator = readkeys.iterator();
			while (iterator.hasNext()) {
				SelectionKey key = iterator.next();
				if (key.isAcceptable()) {
					accept(key);
				}
				if (key.isReadable()) {
					receive(key);
				}
				if (key.isWritable()) {
					send(key);
				}
				iterator.remove();
			}
		}
	}

	// 处理接收连接就绪事件
	private void accept(SelectionKey key) throws Exception {
		SocketChannel socketChannel = serverSocketChannel.accept();
		System.out.println("收到了客户端连接，来自" + socketChannel.getRemoteAddress());
		socketChannel.configureBlocking(false);
		ByteBuffer buffer = ByteBuffer.allocate(1024);
		socketChannel.register(selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE, buffer);
	}

	// 处理读就绪事件
	private void receive(SelectionKey key) throws Exception {
		SocketChannel socketChannel = (SocketChannel) key.channel();
		ByteBuffer buffer = (ByteBuffer) key.attachment();
//		buffer.limit(buffer.capacity());
//		socketChannel.read(buffer);
		
		 ByteBuffer readBuffer=ByteBuffer.allocate(32);
		 socketChannel.read(readBuffer);
		 System.out.println(readBuffer.position() + " " + readBuffer.limit());
		 readBuffer.flip();
		 System.out.println(readBuffer.position() + " " + readBuffer.limit());
		 buffer.limit(buffer.capacity());
		 buffer.put(readBuffer);
	}

	// 处理写就绪事件
	private void send(SelectionKey key) throws Exception {
		SocketChannel socketChannel = (SocketChannel) key.channel();
		ByteBuffer buffer = (ByteBuffer) key.attachment();
		buffer.flip();
		String data = charset.decode(buffer).toString();
		if (data.indexOf("\r\n") == -1)
			return;
		String firstLine = data.substring(0, data.indexOf("\n") + 1);
		ByteBuffer outputBuffer = charset.encode("echo:" + firstLine);
		while (outputBuffer.hasRemaining())
			socketChannel.write(outputBuffer);
		ByteBuffer temp = charset.encode(firstLine);
		buffer.position(temp.limit());
		buffer.compact();

		if (firstLine.equals("bye")) {
			socketChannel.close();
			key.cancel();
			System.out.println("客户端断开连接");
		}
	}

	public static void main(String[] args) throws Exception {
		new EchoSever().service();
	}
}